import axios, { AxiosInstance, AxiosRequestConfig, CancelTokenSource } from 'axios'
import { Loading } from 'element-ui'
import { getToken } from '@/utils/auth'
import { HttpStatusCode } from '@/common/enums'
import { Encrypt, Decrypt } from './cryptor';
import { Current } from "@/config.js";
import { errorMessage, networkError } from '@/utils/common';

const urlReg = /(https?|ftp|file):\/\/[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]/g; // 匹配url的正则
const isTestDevice = () => window.location.hash.includes('/test');

/**
 * @description 获取baseURL
 */
const getBaseURL = (): string => {
  if (process.env.VUE_APP_PLATFORM == 'webview') {
    return (localStorage.getItem('baseURL') || "") + "/api/cms/app/";
  }
  if (process.env.VUE_APP_PLATFORM == 'web') {
    let ENV = "";
    if (process.env.NODE_ENV == 'development') {
      // ENV = "/TEST";
      // ENV = "/TEST";
      // ENV = "/RELEASE";
      // ENV = "/MASTER";
      ENV = "/" + Current;
    }
    return ENV + '/api/cms/' + (isTestDevice() ? 'app' : 'web');
  }
  return '';
}

/**
 * @description 获取axios实例
 */
const getInstance = (): AxiosInstance => {
  const instance = axios.create({
    baseURL: getBaseURL(),
    // timeout: 5000 // 毫秒
  });
  instance.interceptors.request.use(
    (config) => {
      if (config.loading) {
        config.loadingInstance = Loading.service({
          lock: true,
        });
        setTimeout(() => {
          config.loadingInstance.close();
        }, 60 * 1000);
      }
      if (config.headers) {
        if (process.env.VUE_APP_PLATFORM == "webview" || isTestDevice()) {
          config.headers['marketCode'] = '' + localStorage.getItem('marketCode') || "";
          config.headers['Content-Type'] = "application/json";
        } else {
          config.headers['token'] = getToken()
        }
      }
      if ((process.env.VUE_APP_PLATFORM == "webview" || isTestDevice()) && localStorage.getItem('debug') != 'true') {
        if (config.crypto == null || config.crypto === true) {
          // crypto不填或者填true都表示要加密
          console.log(`${config.method}-${config.url}`, config.data);
          config.data = Encrypt(JSON.stringify(config.data));
        }
      }
      return config
    },
    error => {
      console.log(error) // for debug
      return Promise.reject(error)
    }
  )
  instance.interceptors.response.use(
    response => {
      if (response.config.loadingInstance) {
        response.config.loadingInstance.close();
      }
      if (process.env.VUE_APP_PLATFORM == "webview" || isTestDevice()) {
        if (response.config.crypto == null || response.config.crypto == true) {
          if (localStorage.getItem('debug') != 'true') {
            try {
              response.data = JSON.parse(Decrypt(response.data));
            } catch (error) {
              localStorage.removeItem('pubKey');
              errorMessage("密钥已失效");
              return;
            }
          }
          console.log(`${response.config.url}`, response.data);
        }
      }
      const { data } = response;
      if (data.code === HttpStatusCode.Success) {
        return data;
      }
      errorMessage(data.message);
      if (data.code === HttpStatusCode.Unauthorized) {
        const portalUrl = localStorage.getItem('portalUrl') || ''
        localStorage.clear()
        localStorage.setItem('portalUrl', portalUrl)
        if (process.env.NODE_ENV !== 'development') {
          window.location.replace(localStorage.getItem('portalUrl') || "https://portal.demo.reconova.com/");
        }
      }
      return Promise.reject(new Error(data.message))
    },
    error => {
      if (error.message == "Network Error") {
        networkError();
      }
      // errorMessage(error.message);
      return Promise.reject(error)
    }
  )
  return instance;
}

const CancelToken = axios.CancelToken;
let source: CancelTokenSource | null = CancelToken.source();
/**
 * @description 取消所有已经发出去的请求
 * @param message 错误消息
 */
export const cancelHttp = (message?: string) => {
  source!.cancel(message);
  source = null; // 触发GC
  source = CancelToken.source();
}

// 原则是尽可能利用axios原有优雅的api，不做过多无意义的封装
let instance = getInstance();
// 这里提供了原生axios接口的api，只有统一拦截器，没有接口取消功能
export default instance;

/**
 * @description 更新axios实例，目的为了更新baseURL
 */
export const updateAxios = (): void => {
  instance = getInstance();
}

// 这里提供二次封装的api，包含接口取消功能
export const request = (url: string, config: AxiosRequestConfig) => {
  // config.cancelToken = source!.token;
  return instance({
    ...config,
    url
  });
};

// 更进一步提供方便传参的get和post方法
export const get = (url: string, params?: unknown, config?: AxiosRequestConfig) => request(url, {
  ...config,
  method: 'get',
  params,
});
export const post = (url: string, data?: unknown, config?: AxiosRequestConfig) => request(url, {
  ...config,
  method: 'post',
  data,
});
export const put = (url: string, data?: unknown, config?: AxiosRequestConfig) => request(url, {
  ...config,
  method: 'put',
  data,
});

export const Delete = (url: string, data?: unknown, config?: AxiosRequestConfig) => request(url, {
  ...config,
  method: 'delete',
  data,
});